package gui.product;


import facades.ProductFacade;
import gui.common.Controller;
import gui.common.DataConverter;
import gui.common.IView;
import gui.common.SizeUnits;
import gui.inventory.ProductContainerData;

import java.util.HashMap;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;

import plugin.BarcodeFinderRegistry;

import coreModel.Barcode;
import coreModel.Product;
import coreModel.ProductContainer;
import coreModel.Supply;
import coreModel.Unit;

/**
 * Controller class for the add item view.
 */
public class AddProductController extends Controller implements IAddProductController, Observer
{

	private Map<Product,ProductData> productObjToProductData;
	private ProductContainerData parentPointer;
	private int count;
	private boolean countChanged=false;
	
	private String fetchedDesc;
	private BarcodeFinderRegistry bcFinder; 
	
	private final String SEARCH_MESSAGE = "Identifying Product - Please Wait";
	
	/**
	 * Constructor.
	 * 
	 * @param view Reference to the add product view
	 * @param barcode Barcode for the product being added
	 * @param count 
	 */
	public AddProductController(IView view, String barcode,
			ProductContainerData parentPointer, int count) 
	{
		super(view);

//		construct();
		fetchedDesc = SEARCH_MESSAGE;
		bcFinder = new BarcodeFinderRegistry();
		bcFinder.setBarcode(barcode);
		bcFinder.addObserver(this);
		toggleAllComponents(false);
		findDesc();
		
		
		productObjToProductData= new HashMap<Product,ProductData>();
		this.parentPointer=parentPointer;

		//set default values
		getView().setBarcode(barcode);
		getView().setSizeUnit(getView().getSizeUnit());
		getView().setShelfLife("0");
		getView().setSizeUnit(SizeUnits.Count);
		this.count=count;
		getView().setSizeValue(""+count);
		getView().setSupply("0");
		getView().enableBarcode(false);
		
		
		/*
		 * find barcode
		 */
		
	}

	private void toggleAllComponents(boolean on)
	{
		this.getView().enableDescription(on);
		this.getView().enableOK(on);
		this.getView().enableShelfLife(on);
		this.getView().enableSizeUnit(on);
		this.getView().enableSizeValue(on);
		this.getView().enableSupply(on);
		this.getView().setDescription(fetchedDesc);
	}

	//
	// Controller overrides
	//

	private void findDesc()
	{		
		Thread finderThread = new Thread(bcFinder);
		finderThread.start();
	}

	/**
	 * Returns a reference to the view for this controller.
	 * 
	 * {@pre None}
	 * 
	 * {@post Returns a reference to the view for this controller.}
	 */
	@Override
	protected IAddProductView getView() {
		return (IAddProductView)super.getView();
	}

	/**
	 * Sets the enable/disable state of all components in the controller's view.
	 * A component should be enabled only if the user is currently
	 * allowed to interact with that component.
	 * 
	 * {@pre None}
	 * 
	 * {@post The enable/disable state of all components in the controller's view
	 * have been set appropriately.}
	 */
	@Override
	protected void enableComponents() 
	{

		sizeUnitLogic();
		boolean enable=true;
		//in future phase we will need to check the Internet for this product


		//is there a description
		if (getView().getDescription().length()>0)
			enable =enable &true;
		else
			enable=false;

		// there is a description and it is non negative
		try
		{
			//check shelf life
			if(enable &&
					(Integer.parseInt(getView().getShelfLife()))>=0 &&
					getView().getShelfLife().length()>0) 
			{
				enable=enable&true;
			}
			else 
				enable=false;

			//checks to see if the supply can be created
			if(getView().getSizeUnit()==SizeUnits.Count)
			{
				Supply tmpSupply = new Supply(Integer.parseInt
						(getView().getSizeValue()),Unit.COUNT);
			}
			else
			{
				float value =Float.parseFloat(getView().getSizeValue());
				Supply tmpSupply = new Supply(value,
						DataConverter.toEnum(getView().getSizeUnit()));
				//check to make sure not zero
				if(value<=0)
					enable= false;
			}

			//check barcode
			enable =checkBarcode(enable);

			//check to make sure supply is positive
			int threeMonth= Integer.parseInt(getView().getSupply());
			if(threeMonth<0)
				enable=false;

		}
		// if the there is a non numeric value in the supply or shelf life
		catch(Exception e)
		{
			enable=false;
		}
		getView().enableOK(enable);

		// enable count element



	}
	
	private boolean checkBarcode(boolean enable)
	{
		//check barcode
		if(enable && getView().getBarcode().length()>0 ) 
		{
			return enable&true;
		}
		else 
			return false;
	}

	private void sizeUnitLogic()
	{
		if(getView().getSizeUnit()==SizeUnits.Count)
		{
			countChanged=false;
			getView().enableSizeValue(false);
			getView().setSizeValue("1");
		}
		else
		{
			if(countChanged==false)
			{
				getView().setSizeValue("0");
				countChanged=true;
			}
			getView().enableSizeValue(true);

		}
	}

	/**
	 * Loads data into the controller's view.
	 * 
	 *  {@pre None}
	 *  
	 *  {@post The controller has loaded data into its view}
	 */

	protected void loadValues(ProductData prod) 
	{
		getView().setBarcode(prod.getBarcode());
		getView().setDescription(prod.getDescription());
		getView().setShelfLife(prod.getShelfLife());
		getView().setSizeUnit(prod.getSizeUnit());
		getView().setSizeValue(prod.getSize());
		getView().setSupply(prod.getSupply());
	}

	//
	// IAddProductController overrides
	//

	/**
	 * This method is called when any of the fields in the
	 * add product view is changed by the user.
	 */
	@Override
	public void valuesChanged() 
	{
		enableComponents();

	}

	/**
	 * This method is called when the user clicks the "OK"
	 * button in the add product view.
	 */
	@Override
	public void addProduct() 
	{
		Product tmp;
		try
		{
			tmp = new Product(getView().getDescription(), 
					new Barcode(getView().getBarcode()));
			tmp.setShelfLife(Integer.parseInt(getView().getShelfLife()));
			tmp.setThreeMonthSupply(Integer.parseInt(getView().getSupply()));
			Supply tmpSupply;
			//parse int for count
			if(getView().getSizeUnit()==SizeUnits.Count)
			{
				tmpSupply = new Supply (1,
						DataConverter.toEnum(getView().getSizeUnit()));
			}
			//parse 
			else
			{
				tmpSupply = new Supply (Float.parseFloat(getView().getSizeValue()),
						DataConverter.toEnum(getView().getSizeUnit()));
			}

			tmp.setSupply(tmpSupply);

			//current point of failure because other classes are not 
			//implemented so the reference is still null
			ProductFacade.getInstance().addProduct(tmp,(ProductContainer)parentPointer.getTag());
		}
		catch (Exception e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	/**
	 * this method processes the "Cancel" click received from the view
	 * @return true if the view needs to exit. false we are just canceling the product search.
	 */
	public boolean cancel()
	{
		if (bcFinder.searching())
		{
			bcFinder.stopSearch();
			fetchedDesc = "";
			toggleAllComponents(true);
			enableComponents();
			return false;
		}
		
		return true;
	}

	@Override
	public void update(Observable o, Object arg)
	{
		fetchedDesc = (String)arg;
		toggleAllComponents(true);
		enableComponents();
	}


}








